package com.syzg.common.dao.impl;

import com.syzg.common.dao.BaseDAO;
import com.syzg.common.util.SearchMap;
import com.syzg.core.page.DefaultPageResult;
import com.syzg.core.page.PageResult;
import java.io.Serializable;
import java.util.List;
import javax.annotation.Resource;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Projections;
import org.springframework.transaction.annotation.Transactional;

public abstract class BaseDAOHibernate<T>
  implements BaseDAO<T>
{

  @Resource
  private SessionFactory sessionFactory;

  protected abstract Class<?> getEntityClass();

  protected Session getSession()
  {
    return this.sessionFactory.getCurrentSession();
  }

  @Transactional
  public Object findObjectById(Serializable id, Class<?> objectClass) {
    return getSession().get(objectClass, id);
  }

  @Transactional
  public T findObjectById(Serializable id)
  {
    return (T)findObjectById(id, getEntityClass());
  }

  @Transactional
  public void create(Object obj) {
    getSession().save(obj);
  }

  @Transactional
  public void update(Object obj) {
    getSession().update(obj);
  }

  @Transactional
  public void delete(Object obj) {
    getSession().delete(obj);
  }

  @Transactional
  public void delete(Serializable id) {
    delete(id, getEntityClass());
  }

  @Transactional
  public void delete(Serializable id, Class<?> objectClass) {
    Object object = findObjectById(id, objectClass);
    if (object != null) delete(object); 
  }

  @Transactional
  public void delete(Serializable[] ids)
  {
    for (int i = 0; i < ids.length; i++)
      delete(ids[i]);
  }

  @Transactional
  public void delete(Serializable[] ids, Class<?> objectClass) {
    for (int i = 0; i < ids.length; i++)
      delete(ids[i], objectClass);
  }

  @Transactional
  public List<Object> findObjects(SearchMap searchMap)
  {
    searchMap.putOrderToUse();
    Criteria criteria = searchMap.getCriteria(getSession());
    return criteria.list();
  }

  @Transactional
  public PageResult findObjectsForPage(int pageNo, int pageSize, SearchMap searchMap)
  {
    Criteria criteria = searchMap.getCriteria(getSession());
    Long l = (Long)criteria.setProjection(Projections.rowCount()).uniqueResult();
    int totalCount = l.intValue();
    criteria.setProjection(null);
    criteria.setResultTransformer(Criteria.ROOT_ENTITY);
    searchMap.putOrderToUse();
    List items = criteria.setFirstResult((pageNo - 1) * pageSize).setMaxResults(pageSize).list();
    PageResult pageResult = new DefaultPageResult(items, totalCount, (pageNo - 1) * pageSize, pageSize);
    return pageResult;
  }

  @Transactional
  public long getCount(SearchMap searchMap) {
    Criteria criteria = searchMap.getCriteria(getSession());
    Long count = (Long)criteria.setProjection(Projections.rowCount()).uniqueResult();
    return count.longValue();
  }

  @Transactional
  public boolean isExist(Serializable id, String[] propertyNames, String[] propertyValues) {
    return isExist(id, propertyNames, propertyValues, getEntityClass());
  }

  @Transactional
  public boolean isExist(Serializable id, String[] propertyNames, String[] propertyValues, Class<?> objectClass) {
    long count = 0L;
    SearchMap searchMap = SearchMap.forClass(objectClass);
    if (id != null) {
      searchMap.notEq("id", id);
    }
    if ((propertyNames != null) && (propertyValues != null)) {
      for (int i = 0; i < propertyNames.length; i++) {
        searchMap.eq(propertyNames[i], propertyValues[i]);
      }
    }

    count = getCount(searchMap);
    return count > 0L;
  }

  @Transactional
  public int executeHql(String hql) {
    Session session = getSession();
    Query query = session.createQuery(hql);
    return query.executeUpdate();
  }

  @Transactional
  public int executeSql(String sql) {
    Session session = getSession();
    SQLQuery sqlQuery = session.createSQLQuery(sql);
    return sqlQuery.executeUpdate();
  }
}